#include "edge_plugin.h"

#include "ui_plugin.h"


#define DERIVATIVES_PAGE                0
#define CANNY_PAGE                      1
#define CONTOUR_PAGE                    2

Edge_Plugin::Edge_Plugin()
{
    // Insert initialization codes here ...
}

Edge_Plugin::~Edge_Plugin()
{
    // Insert cleanup codes here ...
}

QString Edge_Plugin::title()
{
    return this->metaObject()->className();
}

QString Edge_Plugin::version()
{
    return "1.0.0";
}

QString Edge_Plugin::description()
{
    return "Performs different filters available in OpenCV";
}

QString Edge_Plugin::help()
{
    return "This is a plugin that performs different filters available in OpenCV";
}

void Edge_Plugin::setupUi(QWidget *parent)
{
    ui = new Ui::PluginGui;
    ui->setupUi(parent);

    ui->mainTabs->setCurrentIndex(0);

    connect(ui->mainTabs, SIGNAL(currentChanged(int)), this, SLOT(on_mainTabs_currentChanged(int)));

    connect(ui->derivSobelRadio, SIGNAL(toggled(bool)), this, SLOT(on_derivSobelRadio_toggled(bool)));
    connect(ui->derivScharrRadio, SIGNAL(toggled(bool)), this, SLOT(on_derivScharrRadio_toggled(bool)));
    connect(ui->derivLaplacRadio, SIGNAL(toggled(bool)), this, SLOT(on_derivLaplacRadio_toggled(bool)));
    connect(ui->derivDeltaSpin, SIGNAL(valueChanged(double)), this, SLOT(on_derivDeltaSpin_valueChanged(double)));
    connect(ui->derivScaleSpin, SIGNAL(valueChanged(double)), this, SLOT(on_derivScaleSpin_valueChanged(double)));
    connect(ui->derivKsizeSpin, SIGNAL(valueChanged(int)), this, SLOT(on_derivKsizeSpin_valueChanged(int)));

    connect(ui->cannyThresh1Spin, SIGNAL(valueChanged(int)), this, SLOT(on_cannyThresh1Spin_valueChanged(int)));
    connect(ui->cannyThresh2Spin, SIGNAL(valueChanged(int)), this, SLOT(on_cannyThresh2Spin_valueChanged(int)));
    connect(ui->cannyKsizeSpin, SIGNAL(valueChanged(int)), this, SLOT(on_cannyKsizeSpin_valueChanged(int)));

    connect(ui->contourTh1Spin, SIGNAL(valueChanged(int)), this, SLOT(on_contourTh1Spin_valueChanged(int)));
    connect(ui->contourTh2Spin, SIGNAL(valueChanged(int)), this, SLOT(on_contourTh2Spin_valueChanged(int)));
    connect(ui->contourModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_contourModeBox_currentIndexChanged(int)));
    connect(ui->contourMethBox, SIGNAL(currentIndexChanged(int)), this, SLOT(on_contourMethBox_currentIndexChanged(int)));

    connect(ui->deriUrlLabel1,SIGNAL(linkActivated(QString)),this,SLOT(openURL(QString)));
    connect(ui->deriUrlLabel2,SIGNAL(linkActivated(QString)),this,SLOT(openURL(QString)));
    connect(ui->cannyUrl,SIGNAL(linkActivated(QString)),this,SLOT(openURL(QString)));
    connect(ui->contourUrl,SIGNAL(linkActivated(QString)),this,SLOT(openURL(QString)));

}

void Edge_Plugin::processImage(const cv::Mat &inputImage, cv::Mat &outputImage)
{
    using namespace cv;
    using namespace std;
    Mat gray;
    cvtColor(inputImage, gray, COLOR_BGR2GRAY);

    switch(ui->mainTabs->currentIndex())
    {

        case DERIVATIVES_PAGE:
        {
            GaussianBlur(gray, gray, Size(3, 3), 0);
            Mat grad_x, grad_y;
            Mat abs_grad_x, abs_grad_y;

            if(ui->derivSobelRadio->isChecked()){

                Sobel(gray, grad_x, CV_16S, 1, 0, ui->derivKsizeSpin->value(), ui->derivScaleSpin->value(), ui->derivDeltaSpin->value());
                Sobel(gray, grad_y, CV_16S, 0, 1, ui->derivKsizeSpin->value(), ui->derivScaleSpin->value(), ui->derivDeltaSpin->value());

                // converting back to CV_8U
                convertScaleAbs(grad_x, abs_grad_x);
                convertScaleAbs(grad_y, abs_grad_y);
                addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, gray);
                cvtColor(gray, outputImage, COLOR_GRAY2BGR);
            }

            else if(ui->derivScharrRadio->isChecked()){

                Scharr(gray, grad_x, CV_16S, 1, 0, ui->derivScaleSpin->value(), ui->derivDeltaSpin->value());
                Scharr(gray, grad_y, CV_16S, 0, 1, ui->derivScaleSpin->value(), ui->derivDeltaSpin->value());

                // converting back to CV_8U
                convertScaleAbs(grad_x, abs_grad_x);
                convertScaleAbs(grad_y, abs_grad_y);
                addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, gray);
                cvtColor(gray, outputImage, COLOR_GRAY2BGR);
            }
            else if(ui->derivLaplacRadio->isChecked()){
                Mat inputimg=gray.clone();
                Laplacian(inputimg, gray, CV_16S, ui->derivKsizeSpin->value(), ui->derivScaleSpin->value(), ui->derivDeltaSpin->value());

                // converting back to CV_8U
                convertScaleAbs(gray, gray);
                cvtColor(gray, outputImage, COLOR_GRAY2BGR);
            }
            break;
        }

        case CANNY_PAGE:
        {
            blur(gray, gray, Size(3, 3));
            Mat inputimg=gray.clone();
            Canny(inputimg, gray, ui->cannyThresh1Spin->value(), ui->cannyThresh2Spin->value(),ui->cannyKsizeSpin->value());
            cvtColor(gray, outputImage, COLOR_GRAY2BGR);
            break;
        }

        case CONTOUR_PAGE:
        {

            Mat canny_output;
            vector< vector<Point> > contours;
            vector<Vec4i> hierachy;

            Canny(gray, canny_output, ui->contourTh1Spin->value(), ui->contourTh2Spin->value());
            findContours(canny_output, contours, hierachy, ui->contourModeBox->currentIndex(),
                         ui->contourMethBox->currentIndex(), Point(0, 0));

            Mat dst = Mat::zeros(gray.size(), CV_8UC3);
            for (size_t i = 0; i < contours.size(); i++) {
                drawContours(dst, contours, i, Scalar(255,255,255), 1, LINE_AA, hierachy, 0, Point(0, 0));
            }
            outputImage=dst.clone();
            break;
        }

        default:
            break;

    }
//    cvtColor(gray, outputImage, COLOR_GRAY2BGR);
}


void Edge_Plugin::on_mainTabs_currentChanged(int index)
{
    Q_UNUSED(index);
    emit updateNeeded();
}

void Edge_Plugin::on_derivSobelRadio_toggled(bool checked)
{
    Q_UNUSED(checked);
   init(true);
   ui->derivText->setText("C++ API:<br>"
                          "void Sobel( <br>"
                          " ""InputArray  src, <br>"
                          " ""OutputArray dst, <br>"
                          " ""int ddepth, <br>"
                          " ""int dx, <br>"
                          " ""int dy, <br>"
                          " ""int ksize = 3, <br>"
                          " ""double scale = 1, <br>"
                          " ""double delta = 0, <br>"
                          " ""int borderType = BORDER_DEFAULT <br>"
                          ")"
                          );
    emit updateNeeded();
}

void Edge_Plugin::on_derivScharrRadio_toggled(bool checked)
{
    Q_UNUSED(checked);
    init(false);
    ui->derivText->setText("C++ API:<br>"
                           "void Scharr( <br>"
                           "  ""InputArray  src, <br>"
                           "  ""OutputArray dst, <br>"
                           "  ""int ddepth, <br>"
                           "  ""int dx, <br>"
                           "  ""int dy, <br>"
                           "  ""double scale = 1, <br>"
                           "  ""double delta = 0, <br>"
                           "  ""int borderType = BORDER_DEFAULT <br>"
                           ")"
                           );
    emit updateNeeded();
}

void Edge_Plugin::on_derivLaplacRadio_toggled(bool checked)
{
    Q_UNUSED(checked);
    init(true);
    ui->derivText->setText("C++ API:<br>"
                          "void cv::Laplacian( <br>"
                          "  ""InputArray  src, <br>"
                          "  ""OutputArray dst, <br>"
                          "  ""int ddepth, <br>"
                          "  ""int ksize = 1, <br>"
                          "  ""double scale = 1, <br>"
                          "  ""double delta = 0, <br>"
                          "  ""int borderType = BORDER_DEFAULT <br>"
                          ")"
                          );
    emit updateNeeded();
}

void Edge_Plugin::on_derivScaleSpin_valueChanged(double arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Edge_Plugin::on_derivDeltaSpin_valueChanged(double arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Edge_Plugin::on_derivKsizeSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Edge_Plugin::on_cannyThresh1Spin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Edge_Plugin::on_cannyThresh2Spin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Edge_Plugin::on_cannyKsizeSpin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Edge_Plugin::on_contourTh1Spin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Edge_Plugin::on_contourTh2Spin_valueChanged(int arg1)
{
    Q_UNUSED(arg1);
    emit updateNeeded();
}

void Edge_Plugin::on_contourModeBox_currentIndexChanged(int index)
{
    Q_UNUSED(index);
    emit updateNeeded();
}

void Edge_Plugin::on_contourMethBox_currentIndexChanged(int index)
{
    Q_UNUSED(index);
    emit updateNeeded();
}

void Edge_Plugin::init(bool a)
{

    ui->derivKsizeSpin->setEnabled(a);

    ui->derivKsizeSpin->setValue(3);
    ui->derivScaleSpin->setValue(1.00);
    ui->derivDeltaSpin->setValue(0.00);
}

void Edge_Plugin::openURL(QString url)
{
    QDesktopServices::openUrl(url);
}

